package com.hc.api.utils;

import com.hc.comm.token.AccessToken;
import com.hc.comm.utils.ExceptionUtils;
import com.hc.comm.utils.SecurityUtils;
import com.hc.comm.utils.SpringUtils;
import com.hc.service.model.LoginInfoModel;
import com.hc.service.model.ShareRecordModel;
import com.hc.service.model.UserdataModel;
import com.hc.service.service.ILoginInfoService;
import com.hc.service.service.IShareRecordService;
import com.hc.service.service.IUserdataService;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.net.URLEncoder;
import java.util.*;


/**
 * @author
 * @date 2015年12月17日 下午10:45:10
 */
public class TokenUtils {

    public static final String TOKEN_NAME = "access_token";
    public static final String SHARE_TOKEN = "share_token";

    /**
     * 生成Token
     *
     * @param user_id
     * @return
     * @throws Exception String
     * @date 2016年2月18日 下午1:31:32
     */
    public static String generateAccessToken(Long user_id) throws Exception {
        AccessToken accessToken = TokenUtils
                .getTokenOriginal(new AccessToken(user_id));
        if (accessToken == null) {
            ExceptionUtils.throwBaseException("生成token异常");
        }
        StringBuilder sb = new StringBuilder(user_id.toString());
        sb.append("@");
        sb.append(SecurityUtils.md5(accessToken.getAccessToken()));
        return sb.toString();
    }

    /**
     * 解析token
     *
     * @param request
     * @return
     * @throws Exception HttpServletRequest
     * @date 2016年1月31日 下午12:42:50
     */
    public static AccessToken getAccessToken(HttpServletRequest request)
            throws Exception {
        if (request == null) {
            ExceptionUtils.throwBaseException("参数异常");
        }
        String originToken = request.getParameter(TOKEN_NAME);
        if (StringUtils.isBlank(originToken)) {
            return null;
        }
        String[] tokens = originToken.split("@");
        if (tokens.length <= 1) {
            ExceptionUtils.throwBaseException("Token信息不合法");
        }
        return new AccessToken(Long.valueOf(tokens[0]), originToken);
    }

    /**
     * 加密串
     *
     * @param accessToken
     * @return
     * @throws Exception StringBuilder
     * @date 2016年1月31日 上午10:52:47
     */
    private static AccessToken getTokenOriginal(AccessToken accessToken)
            throws Exception {
        if (accessToken == null || accessToken.getUser_id() == null) {
            ExceptionUtils.throwBaseException("参数异常");
        }

        UserdataModel uModel = getUserService()
                .getByPrimaryKey(accessToken.getUser_id());

        LoginInfoModel loginInfoModel = getLogininfoService()
                .getRecentLoginInfo(uModel.getId());
        if (uModel == null) {
            ExceptionUtils.throwBaseException("用户不存在");
        }
        if (loginInfoModel == null) {
            ExceptionUtils.throwBaseException("没有登录记录");
        }
        String token = TokenUtils.getAccessToken(uModel.getId(),
                uModel.getPassword(), uModel.getSalt(),
                uModel.getDeviceId(),
                loginInfoModel.getCreateTime());
        accessToken.setAccessToken(token);
        return accessToken;

    }

    /**
     * 加密串
     *
     * @param accountId
     * @param password
     * @param salt
     * @param deviceStatus
     * @param lastLoginTime
     * @return String
     * @date 2016年1月31日 下午12:29:35
     */
    private static String getAccessToken(Long accountId, String password,
                                         String salt, String deviceStatus, Long lastLoginTime) {
        if (accountId == null || deviceStatus == null
                || lastLoginTime == null) {
            ExceptionUtils.throwBaseException("参数异常");
        }

        StringBuilder tokenOriginal = new StringBuilder();
        tokenOriginal.append(accountId);
        tokenOriginal.append(password);
        tokenOriginal.append(salt);
        tokenOriginal.append(deviceStatus);
        tokenOriginal.append(lastLoginTime);
        return tokenOriginal.toString();
    }


    protected static IUserdataService getUserService() {
        return (IUserdataService) SpringUtils.getBean("userdataService");
    }

    protected static ILoginInfoService getLogininfoService() {
        return (ILoginInfoService) SpringUtils.getBean("loginInfoService");
    }

    /**
     * 生成分享记录的token
     *
     * @param shareRecordId 分享记录的id
     * @return
     * @throws Exception
     */
    public static String generateShareToken(int shareRecordId) throws Exception {
        if (shareRecordId == 0) {
            ExceptionUtils.throwBaseException("参数异常!");
        }
        ShareRecordModel shareRecordModel = getShareRecordService().getByPrimaryKey(shareRecordId);
        if (shareRecordModel == null) {
            ExceptionUtils.throwBaseException("生成分享token失败!");
        }

        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(shareRecordModel.getContentId());
        stringBuilder.append(shareRecordModel.getId());
        stringBuilder.append(shareRecordModel.getCreateTime());
        stringBuilder.append(SHARE_TOKEN);
        String tokenStr = SecurityUtils.md5(stringBuilder.toString());
        if (StringUtils.isEmpty(tokenStr)) {
            ExceptionUtils.throwBaseException("生成token异常!");
        }
        StringBuilder shareToken = new StringBuilder();
        shareToken.append(shareRecordModel.getId());
        shareToken.append("-");
        shareToken.append(tokenStr);
        System.out.println("生成的shareToken:" + shareToken);
        return shareToken.toString();
    }


    protected static IShareRecordService getShareRecordService() {
        return (IShareRecordService) SpringUtils.getBean("shareRecordService");
    }

    /**
     * 方法用途: 对所有传入参数按照字段名的 ASCII 码从小到大排序（字典序），并且生成url参数串<br>
     * 实现步骤: <br>
     *
     * @param paraMap    要排序的Map对象
     * @param urlEncode  是否需要URLENCODE
     * @param keyToLower 是否需要将Key转换为全小写
     *                   true:key转化成小写，false:不转化
     * @return
     */
    public static String formatUrlMap(Map<String, String> paraMap, boolean urlEncode, boolean keyToLower) {
        String buff = "";
        Map<String, String> tmpMap = paraMap;
        try {
            List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(tmpMap.entrySet());
            // 对所有传入参数按照字段名的 ASCII 码从小到大排序（字典序）
            Collections.sort(infoIds, new Comparator<Map.Entry<String, String>>() {

                @Override
                public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) {
                    return (o1.getKey()).toString().compareTo(o2.getKey());
                }
            });
            // 构造URL 键值对的格式
            StringBuilder buf = new StringBuilder();
            for (Map.Entry<String, String> item : infoIds) {
                if (StringUtils.isNotBlank(item.getKey())) {
                    String key = item.getKey();
                    String val = item.getValue();
                    if (urlEncode) {
                        val = URLEncoder.encode(val, "utf-8");
                    }
                    if (keyToLower) {
                        buf.append(key.toLowerCase() + "=" + val);
                    } else {
                        buf.append(key + "=" + val);
                    }
                    buf.append("&");
                }

            }
            buff = buf.toString();
            if (buff.isEmpty() == false) {
                buff = buff.substring(0, buff.length() - 1);
            }
        } catch (Exception e) {
            return null;
        }
        return buff;
    }
}
